{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "cellView": "form",
    "id": "a7f65e34937b"
   },
   "outputs": [],
   "source": [
    "# @title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
    "# you may not use this file except in compliance with the License.\n",
    "# You may obtain a copy of the License at\n",
    "#\n",
    "# https://www.apache.org/licenses/LICENSE-2.0\n",
    "#\n",
    "# Unless required by applicable law or agreed to in writing, software\n",
    "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
    "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
    "# See the License for the specific language governing permissions and\n",
    "# limitations under the License."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "c005a2665283"
   },
   "source": [
    "# Representing noise"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "HYkRhx2pe2XX"
   },
   "source": [
    "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
    "  <td>\n",
    "    <a target=\"_blank\" href=\"https://quantumai.google/cirq/noise/representing_noise\"><img src=\"https://quantumai.google/site-assets/images/buttons/quantumai_logo_1x.png\" />View on QuantumAI</a>\n",
    "  </td>\n",
    "  <td>\n",
    "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/quantumlib/Cirq/blob/main/docs/noise/representing_noise.ipynb\"><img src=\"https://quantumai.google/site-assets/images/buttons/colab_logo_1x.png\" />Run in Google Colab</a>\n",
    "  </td>\n",
    "  <td>\n",
    "    <a target=\"_blank\" href=\"https://github.com/quantumlib/Cirq/blob/main/docs/noise/representing_noise.ipynb\"><img src=\"https://quantumai.google/site-assets/images/buttons/github_logo_1x.png\" />View source on GitHub</a>\n",
    "  </td>\n",
    "  <td>\n",
    "    <a href=\"https://storage.googleapis.com/tensorflow_docs/Cirq/docs/noise/representing_noise.ipynb\"><img src=\"https://quantumai.google/site-assets/images/buttons/download_icon_1x.png\" />Download notebook</a>\n",
    "  </td>\n",
    "</table>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "d063c007c647"
   },
   "outputs": [],
   "source": [
    "try:\n",
    "    import cirq\n",
    "except ImportError:\n",
    "    print(\"installing cirq...\")\n",
    "    !pip install --quiet cirq\n",
    "    print(\"installed cirq.\")\n",
    "    import cirq"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "755ba122d550"
   },
   "source": [
    "This doc assumes you have already read the [noisy simulation](../simulate/noisy_simulation.ipynb) tutorial.\n",
    "\n",
    "Cirq provides several built-in tools for representing noise at multiple levels:\n",
    "- Channels, to insert as individual noisy operators\n",
    "- `cirq.NoiseModel`s, for applying noise to entire circuits\n",
    "- `cirq.MeasurementGate` parameters, for changing measurements results\n",
    "\n",
    "This doc describes these options and the types of real-world noise they can be used to represent."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "efe093cfa38e"
   },
   "source": [
    "## Channels\n",
    "\n",
    "Errors in hardware can be broadly separated into two categories: _coherent_ and _incoherent_.\n",
    "\n",
    "**Coherent** errors apply a reversible (but unknown) transformation, such as making every $Z$ gate instead behave as $Z^{1.01}$. This can be represented by inserting [gates](../build/gates.ipynb) into the intended circuit.\n",
    "\n",
    "**Incoherent** errors cause [decoherence](https://en.wikipedia.org/wiki/Quantum_decoherence#Non-unitary_modelling_examples) of the quantum state, and are irreversible as a result. This is equivalent to applying an operation with some probability $0 < P < 1$, and can be represented with Cirq \"channels\". [`ops/common_channels.py`](https://github.com/quantumlib/Cirq/blob/main/cirq-core/cirq/ops/common_channels.py) defines channels for some of the most common incoherent errors, which are described below."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "775a6df1be6d"
   },
   "source": [
    "### Bit flip\n",
    "\n",
    "`cirq.BitFlipChannel` (or `cirq.bit_flip`) is equivalent to applying `cirq.X` with a given probability. This channel is best used to represent state-agnostic bit flip errors in the body of a circuit."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "60f9f3b43759"
   },
   "outputs": [],
   "source": [
    "q0 = cirq.LineQubit(0)\n",
    "circuit = cirq.Circuit(cirq.bit_flip(p=0.2).on(q0), cirq.measure(q0, key='result'))\n",
    "result = cirq.Simulator(seed=0).run(circuit, repetitions=1000)\n",
    "print(result.histogram(key='result'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "b526c2d39fe2"
   },
   "source": [
    "For bit flips which depend on the qubit state, see [Amplitude damping](#amplitude-damping).\n",
    "\n",
    "For measurement error that doesn't affect the quantum state, see [Invert mask](#invert-mask)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "352e1b654056"
   },
   "source": [
    "### Amplitude damping\n",
    "\n",
    "`cirq.AmplitudeDampingChannel` (or `cirq.amplitude_damp`) performs a $|1\\rangle \\rightarrow |0\\rangle$ transformation with some probability `gamma`, leaving the existing $|0\\rangle$ state alone. This channel is best used to represent an idealized form of energy dissipation, where qubits decay from $|1\\rangle$ to $|0\\rangle$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "2e8b3868bf6c"
   },
   "outputs": [],
   "source": [
    "q0 = cirq.LineQubit(0)\n",
    "circuit = cirq.Circuit(\n",
    "    cirq.X(q0), cirq.amplitude_damp(gamma=0.2).on(q0), cirq.measure(q0, key='result')\n",
    ")\n",
    "result = cirq.Simulator(seed=0).run(circuit, repetitions=1000)\n",
    "print(result.histogram(key='result'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "352e1b654056"
   },
   "source": [
    "For state-agnostic bit flips, see [Bit flip](#bit-flip)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "352e1b654056"
   },
   "source": [
    "### Generalized amplitude damping\n",
    "\n",
    "`cirq.GeneralizedAmplitudeDampingChannel` (or `cirq.generalized_amplitude_damp`) is a generalized version of `AmplitudeDampingChannel`. It represent a more realistic bidirectional energy dissipation, in which qubits experience not only decay but also spontaneous excitation. In this channel, `gamma` represents the probability of energy transfer (excitation OR decay) and a new parameter `p` gives the probability that the environment is excited.\n",
    "\n",
    "This is equivalent to excitation with probability `(1-p) * gamma` and decay with probability `p * gamma`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "dd677fbd36df"
   },
   "outputs": [],
   "source": [
    "q0, q1 = cirq.LineQubit.range(2)\n",
    "circuit = cirq.Circuit(\n",
    "    cirq.X(q1),\n",
    "    cirq.generalized_amplitude_damp(gamma=0.2, p=0.2).on_each(q0, q1),\n",
    "    cirq.measure(q0, key='result_0'),\n",
    "    cirq.measure(q1, key='result_1'),\n",
    ")\n",
    "result = cirq.Simulator(seed=0).run(circuit, repetitions=1000)\n",
    "print(\"Starting in |0):\", result.histogram(key='result_0'))\n",
    "print(\"Starting in |1):\", result.histogram(key='result_1'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "2b57b0db415c"
   },
   "source": [
    "### Phase flip or damping\n",
    "\n",
    "`cirq.PhaseFlipChannel` (or `cirq.phase_flip`) is equivalent to applying `cirq.Z` with a given probability `p`. This channel is best used to represent state-agnostic phase flip errors in the body of a circuit."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "0fd69edd7133"
   },
   "outputs": [],
   "source": [
    "q0 = cirq.LineQubit(0)\n",
    "circuit = cirq.Circuit(\n",
    "    cirq.H(q0), cirq.phase_flip(p=0.2).on(q0), cirq.H(q0), cirq.measure(q0, key='result')\n",
    ")\n",
    "result = cirq.Simulator(seed=0).run(circuit, repetitions=1000)\n",
    "print(\"Phase flip:\", result.histogram(key='result'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "2b57b0db415c"
   },
   "source": [
    "`cirq.PhaseDampingChannel` (or `cirq.phase_damp`) is a different way of expressing the same behavior: for any given value of `p`, `PhaseFlipChannel(p=p)` is equivalent to `PhaseDampingChannel(gamma=(1-(2*p-1)**2))`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "665f6c0b5956"
   },
   "outputs": [],
   "source": [
    "q0 = cirq.LineQubit(0)\n",
    "# Convert p=0.2 to gamma\n",
    "p = 0.2\n",
    "gamma = 1 - (2 * p - 1) ** 2\n",
    "print(f\"{gamma=}\")\n",
    "circuit = cirq.Circuit(\n",
    "    cirq.H(q0), cirq.phase_damp(gamma=gamma).on(q0), cirq.H(q0), cirq.measure(q0, key='result')\n",
    ")\n",
    "result = cirq.Simulator(seed=0).run(circuit, repetitions=1000)\n",
    "print(\"Phase damp:\", result.histogram(key='result'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "c64aa7e18262"
   },
   "source": [
    "Note that the results differ despite the same seed and equivalent circuits. This is due to the channels having different operators, which interact differently with Cirq's RNG."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "f45f3d04073b"
   },
   "source": [
    "### Depolarization\n",
    "\n",
    "`cirq.DepolarizingChannel` (or `cirq.depolarize`) is equivalent to applying a randomly-selected Pauli operator to the target qubits. The identity is applied with probability `1-p`; all other Pauli operators have an equal probability `p / (4**n-1)` of being selected. This channel is best used for representing uniformly-distributed decoherence of the target qubit(s) across all Pauli channels."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "bc2911a4bf81"
   },
   "outputs": [],
   "source": [
    "q0, q1, q2 = cirq.LineQubit.range(3)\n",
    "circuit = cirq.Circuit(\n",
    "    cirq.H(q0),  # initialize X basis\n",
    "    cirq.H(q1),  # initialize Y basis\n",
    "    cirq.S(q1),\n",
    "    cirq.depolarize(p=0.2).on_each(q0, q1, q2),\n",
    "    cirq.H(q0),  # return to Z-basis\n",
    "    cirq.S(q1) ** -1,\n",
    "    cirq.H(q1),\n",
    "    cirq.measure(q0, key='result_0'),\n",
    "    cirq.measure(q1, key='result_1'),\n",
    "    cirq.measure(q2, key='result_2'),\n",
    ")\n",
    "result = cirq.Simulator(seed=0).run(circuit, repetitions=1000)\n",
    "# All basis states are equally affected.\n",
    "print(\"X basis:\", result.histogram(key='result_0'))\n",
    "print(\"Y basis:\", result.histogram(key='result_1'))\n",
    "print(\"Z basis:\", result.histogram(key='result_2'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "f45f3d04073b"
   },
   "source": [
    "For noise in just the X or Z channels, see [Bit flip](#bit-flip) or [Phase flip](#phase-flip-or-damping) respectively.\n",
    "\n",
    "### Asymmetric depolarization\n",
    "\n",
    "`cirq.AsymmetricDepolarizingChannel` (or `cirq.asymmetric_depolarize`) is a generalized version of `DepolarizingChannel` which accepts separate probabilities for X, Y, and Z error. It is best used instead of `DepolarizingChannel` when there is a known, nontrivial discrepancy between the different Pauli error modes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "e24b120ea02a"
   },
   "outputs": [],
   "source": [
    "q0, q1, q2 = cirq.LineQubit.range(3)\n",
    "asym_depol = cirq.asymmetric_depolarize(p_x=0, p_y=0.05, p_z=0.2)\n",
    "circuit = cirq.Circuit(\n",
    "    cirq.H(q0),  # initialize X basis\n",
    "    cirq.H(q1),  # initialize Y basis\n",
    "    cirq.S(q1),\n",
    "    asym_depol.on_each(q0, q1, q2),\n",
    "    cirq.H(q0),  # return to Z-basis\n",
    "    cirq.S(q1) ** -1,\n",
    "    cirq.H(q1),\n",
    "    cirq.measure(q0, key='result_0'),\n",
    "    cirq.measure(q1, key='result_1'),\n",
    "    cirq.measure(q2, key='result_2'),\n",
    ")\n",
    "result = cirq.Simulator(seed=0).run(circuit, repetitions=1000)\n",
    "# Basis states are only affected by error in other bases.\n",
    "print(\"X basis:\", result.histogram(key='result_0'))\n",
    "print(\"Y basis:\", result.histogram(key='result_1'))\n",
    "print(\"Z basis:\", result.histogram(key='result_2'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "066ad7cc19f6"
   },
   "source": [
    "### Reset\n",
    "\n",
    "`cirq.Reset` forces a qubit into the $|0\\rangle$ state. This is not a noise channel, but rather a hardware operation which commonly consists of measuring the qubit and applying `X` as needed to return it to the $|0\\rangle$ state."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "b1e207466867"
   },
   "outputs": [],
   "source": [
    "q0 = cirq.LineQubit(0)\n",
    "circuit = cirq.Circuit(cirq.bit_flip(p=0.2).on(q0), cirq.reset(q0), cirq.measure(q0, key='result'))\n",
    "result = cirq.Simulator(seed=0).run(circuit, repetitions=1000)\n",
    "print(result.histogram(key='result'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "baf9cefb1aac"
   },
   "source": [
    "### Custom channels\n",
    "\n",
    "`cirq.MixedUnitaryChannel` (in [`ops/mixed_unitary_channel.py`](https://github.com/quantumlib/Cirq/blob/main/cirq-core/cirq/ops/mixed_unitary_channel.py)) is a customizable channel which can represent any probabilistic mixture of unitary operators. It accepts an optional measurement key to capture which operator was selected."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "293264af084d"
   },
   "outputs": [],
   "source": [
    "q0 = cirq.LineQubit(0)\n",
    "# equivalent to cirq.bit_flip(p=0.2)\n",
    "my_channel = cirq.MixedUnitaryChannel(\n",
    "    [(0.8, cirq.unitary(cirq.I)), (0.2, cirq.unitary(cirq.X))], key='op_num'\n",
    ")\n",
    "circuit = cirq.Circuit(my_channel.on(q0), cirq.measure(q0, key='result'))\n",
    "result = cirq.Simulator(seed=0).run(circuit, repetitions=20)\n",
    "# `op_num` and `result` are always equal.\n",
    "print(result)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "baf9cefb1aac"
   },
   "source": [
    "`cirq.KrausChannel` (in [`ops/kraus_channel.py`](https://github.com/quantumlib/Cirq/blob/main/cirq-core/cirq/ops/kraus_channel.py)) is similar, but supports non-unitary operators."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "5259ad5c61c5"
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "q0 = cirq.LineQubit(0)\n",
    "# equivalent to cirq.amplitude_damp(gamma=0.2)\n",
    "gamma = 0.2\n",
    "my_channel = cirq.KrausChannel(\n",
    "    [\n",
    "        np.array([[0, np.sqrt(gamma)], [0, 0]]),  # decay |1) -> |0)\n",
    "        np.array([[1, 0], [0, np.sqrt(1 - gamma)]]),  # stay in |1)\n",
    "    ],\n",
    "    key='op_num',\n",
    ")\n",
    "circuit = cirq.Circuit(cirq.X(q0), my_channel.on(q0), cirq.measure(q0, key='result'))\n",
    "result = cirq.Simulator(seed=0).run(circuit, repetitions=20)\n",
    "# `op_num` and `result` are always equal.\n",
    "print(result)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "baf9cefb1aac"
   },
   "source": [
    "In general, prefer one of the other built-in channels if your use case supports it, as those channels can occasionally be optimized in ways that do not generalize to these channels.\n",
    "\n",
    "Prefer `MixedUnitaryChannel` if your channel has a mix-of-unitaries description, as it can be simulated more efficiently than `KrausChannel`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "b005820d6151"
   },
   "source": [
    "## NoiseModels\n",
    "\n",
    "Built-in `cirq.NoiseModel` types do not have a shared home like channels, but a couple of commonly-used types are listed here. For more complex experiments, it is often useful to define your own `NoiseModel` subclasses; refer to [`devices/noise_model.py`](https://github.com/quantumlib/Cirq/blob/main/cirq-core/cirq/devices/noise_model.py) to learn more."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "ec10d57ac6cf"
   },
   "source": [
    "### Constant noise\n",
    "\n",
    "`cirq.ConstantQubitNoiseModel` (in [`devices/noise_model.py`](https://github.com/quantumlib/Cirq/blob/main/cirq-core/cirq/devices/noise_model.py)) is a simple model which will insert the given gate after every operation in the target circuit. When \"trivially converting\" gates to `NoiseModel`s, this is the model that is used, but it isn't particularly representative of any real-world noise."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "73bdc200ea10"
   },
   "outputs": [],
   "source": [
    "q0 = cirq.LineQubit(0)\n",
    "circuit = cirq.Circuit(\n",
    "    cirq.I(q0), cirq.measure(q0, key='result_0'), cirq.measure(q0, key='result_1')\n",
    ")\n",
    "# Applies noise after every gate, even measurements.\n",
    "noisy_circuit = circuit.with_noise(cirq.X)\n",
    "print(noisy_circuit)\n",
    "result = cirq.Simulator(seed=0).run(noisy_circuit, repetitions=20)\n",
    "print(\"First measure:\", result.histogram(key='result_0'))\n",
    "print(\"Second measure:\", result.histogram(key='result_1'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "ec10d57ac6cf"
   },
   "source": [
    "Avoid using this model except for simple tests, as different gates (particularly `cirq.MeasurementGate`) usually have different error."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "7a247831019f"
   },
   "source": [
    "### Insertion noise\n",
    "\n",
    "`cirq.devices.InsertionNoiseModel` (in [`devices/insertion_noise_model.py`](https://github.com/quantumlib/Cirq/blob/main/cirq-core/cirq/devices/insertion_noise_model.py)) inspects the circuit for operations matching user-specified identifiers, and inserts the corresponding noise operations after matching operations. This noise model is useful for applying specific noise to specific gates - for example, adding different depolarizing error to 1- and 2-qubit gates."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "aafbb3e3ac05"
   },
   "outputs": [],
   "source": [
    "from cirq.devices import InsertionNoiseModel\n",
    "\n",
    "q0 = cirq.LineQubit(0)\n",
    "circuit = cirq.Circuit(cirq.I(q0), cirq.X(q0), cirq.measure(q0, key='result'))\n",
    "# Apply bitflip noise after each X gate.\n",
    "target_op = cirq.OpIdentifier(cirq.XPowGate, q0)\n",
    "insert_op = cirq.bit_flip(p=0.2).on(q0)\n",
    "noise_model = InsertionNoiseModel(\n",
    "    ops_added={target_op: insert_op},\n",
    "    require_physical_tag=False,  # For use outside calibration-to-noise\n",
    ")\n",
    "noisy_circuit = circuit.with_noise(noise_model)\n",
    "print(noisy_circuit)\n",
    "result = cirq.Simulator(seed=0).run(noisy_circuit, repetitions=1000)\n",
    "print(result.histogram(key='result'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "8f5fa4a5f6b3"
   },
   "source": [
    "`InsertionNoiseModel` is primarily used in the calibration-to-noise pipeline, but can be used elsewhere by setting `require_physical_tag=False`, as seen above."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "aa2dd361a7fe"
   },
   "source": [
    "## Measurement parameters\n",
    "\n",
    "`cirq.MeasurementGate` provides parameters for error which occurs in the classical measurement step instead of in the quantum state, which can be useful for accelerating simulations.\n",
    "\n",
    "### Invert mask\n",
    "\n",
    "The `invert_mask` field is a simple list of booleans indicating bits to flip in the final output. This can represent simple bitflip error in measurement, or a correction for that error."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "94f0818ade6a"
   },
   "outputs": [],
   "source": [
    "q0 = cirq.LineQubit(0)\n",
    "circuit = cirq.Circuit(cirq.X(q0), cirq.measure(q0, key='result', invert_mask=[True]))\n",
    "result = cirq.Simulator(seed=0).run(circuit, repetitions=1000)\n",
    "print(result.histogram(key='result'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "aa2dd361a7fe"
   },
   "source": [
    "### Confusion map\n",
    "\n",
    "The `confusion_map` field maps qubit tuples to confusion matrices for those qubits. The confusion matrix for two qubits is:\n",
    "\n",
    "$$\\begin{bmatrix}\n",
    "Pr(00|00) & Pr(01|00) & Pr(10|00) & Pr(11|00) \\\\\n",
    "Pr(00|01) & Pr(01|01) & Pr(10|01) & Pr(11|01) \\\\\n",
    "Pr(00|10) & Pr(01|10) & Pr(10|10) & Pr(11|10) \\\\\n",
    "Pr(00|11) & Pr(01|11) & Pr(10|11) & Pr(11|11)\n",
    "\\end{bmatrix}$$\n",
    "\n",
    "where `Pr(ij|pq)` is the probability of observing `ij` if state `pq` was prepared; a `2**n`-square confusion matrix can be provided for any grouping of N qubits."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "8b8679f784b3"
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "q0 = cirq.LineQubit(0)\n",
    "# 10% chance to report |0) as |1), 20% chance to report |1) as |0).\n",
    "cmap = {(0,): np.array([[0.9, 0.1], [0.2, 0.8]])}\n",
    "circuit = cirq.Circuit(cirq.X(q0), cirq.measure(q0, key='result', confusion_map=cmap))\n",
    "result = cirq.Simulator(seed=0).run(circuit, repetitions=1000)\n",
    "print(result.histogram(key='result'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "aa2dd361a7fe"
   },
   "source": [
    "This can be used for representing more complex errors in measurement, including probabilistic error on individual qubits and correlated error across multiple qubits."
   ]
  }
 ],
 "metadata": {
  "colab": {
   "name": "representing_noise.ipynb",
   "toc_visible": true
  },
  "kernelspec": {
   "display_name": "Python 3",
   "name": "python3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
